home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / util / lev_comp.y < prev    next >
Text File  |  1993-01-16  |  36KB  |  1,529 lines

  1. %{
  2. /*    SCCS Id: @(#)lev_comp.c    3.1    92/07/12    */
  3. /*    Copyright (c) 1989 by Jean-Christophe Collet */
  4. /* NetHack may be freely redistributed.  See license for details. */
  5.  
  6. /*
  7.  * This file contains the Level Compiler code
  8.  * It may handle special mazes & special room-levels
  9.  */
  10.  
  11. /* In case we're using bison in AIX.  This definition must be
  12.  * placed before any other C-language construct in the file
  13.  * excluding comments and preprocessor directives (thanks IBM
  14.  * for this wonderful feature...).
  15.  *
  16.  * Note: some cpps barf on this 'undefined control' (#pragma).
  17.  * Addition of the leading space seems to prevent barfage for now,
  18.  * and AIX will still see the directive in its non-standard locale.
  19.  */
  20.  
  21. #ifdef _AIX
  22.  #pragma alloca        /* keep leading space! */
  23. #endif
  24.  
  25. #include "hack.h"
  26. #include "sp_lev.h"
  27. #ifndef O_WRONLY
  28. # include <fcntl.h>
  29. #endif
  30. #ifndef O_CREAT    /* some older BSD systems do not define O_CREAT in <fcntl.h> */
  31. # include <sys/file.h>
  32. #endif
  33. #ifndef O_BINARY    /* used for micros, no-op for others */
  34. # define O_BINARY 0
  35. #endif
  36.  
  37. #ifdef MICRO
  38. # define OMASK FCMASK
  39. #else
  40. # define OMASK 0644
  41. #endif
  42.  
  43. #define MAX_REGISTERS    10
  44. #define ERR        (-1)
  45.  
  46. #define New(type)        (type *) alloc(sizeof(type))
  47. #define NewTab(type, size)    (type **) alloc(sizeof(type *) * size)
  48.  
  49. #ifdef MICRO
  50. # undef exit
  51. extern void FDECL(exit, (int));
  52. #endif
  53.  
  54. extern void FDECL(yyerror, (char *));
  55. extern void FDECL(yywarning, (char *));
  56. extern int NDECL(yylex);
  57. int NDECL(yyparse);
  58.  
  59. extern char *FDECL(dup_string,(char *));
  60. extern int FDECL(get_floor_type, (CHAR_P));
  61. extern int FDECL(get_room_type, (char *));
  62. extern int FDECL(get_trap_type, (char *));
  63. extern int FDECL(get_monster_id, (char *, CHAR_P));
  64. extern int FDECL(get_object_id, (char *));
  65. extern boolean FDECL(check_monster_char, (CHAR_P));
  66. extern boolean FDECL(check_object_char, (CHAR_P));
  67. extern char FDECL(what_map_char, (CHAR_P));
  68. extern void FDECL(scan_map, (char *));
  69. extern void NDECL(wallify_map);
  70. extern boolean NDECL(check_subrooms);
  71. extern void FDECL(check_coord, (int, int, char *));
  72. extern void NDECL(store_part);
  73. extern void NDECL(store_room);
  74. extern void FDECL(write_maze, (int, specialmaze *));
  75. extern void FDECL(write_lev, (int, splev *));
  76. extern void FDECL(free_rooms, (room **, int));
  77.  
  78. static struct reg {
  79.     int x1, y1;
  80.     int x2, y2;
  81. }        current_region;
  82.  
  83. static struct coord {
  84.     int x;
  85.     int y;
  86. }        current_coord, current_align;
  87.  
  88. static struct size {
  89.     int height;
  90.     int width;
  91. }        current_size;
  92.  
  93. char tmpmessage[256];
  94. altar *tmpaltar[256];
  95. lad *tmplad[256];
  96. stair *tmpstair[256];
  97. digpos *tmpdig[256];
  98. char *tmpmap[ROWNO];
  99. region *tmpreg[256];
  100. lev_region *tmplreg[32];
  101. door *tmpdoor[256];
  102. room_door *tmprdoor[256];
  103. trap *tmptrap[256];
  104. monster *tmpmonst[256];
  105. object *tmpobj[256];
  106. drawbridge *tmpdb[256];
  107. walk *tmpwalk[256];
  108. gold *tmpgold[256];
  109. fountain *tmpfountain[256];
  110. sink *tmpsink[256];
  111. pool *tmppool[256];
  112. engraving *tmpengraving[256];
  113. mazepart *tmppart[10];
  114. room *tmproom[MAXNROFROOMS*2];
  115. corridor *tmpcor[256];
  116.  
  117. static specialmaze maze;
  118. static splev special_lev;
  119. static lev_init init_lev;
  120.  
  121. static char olist[MAX_REGISTERS], mlist[MAX_REGISTERS];
  122. static struct coord plist[MAX_REGISTERS];
  123.  
  124. int n_olist = 0, n_mlist = 0, n_plist = 0;
  125.  
  126. unsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0;
  127. unsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0;
  128. unsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0;
  129. unsigned int nfountain = 0, npool = 0, nsink = 0;
  130.  
  131. static unsigned long lev_flags = 0;
  132.  
  133. unsigned int max_x_map, max_y_map;
  134.  
  135. static xchar in_room;
  136.  
  137. extern int fatal_error;
  138. extern int want_warnings;
  139. extern char* fname;
  140.  
  141. %}
  142.  
  143. %union
  144. {
  145.     int    i;
  146.     char*    map;
  147.     struct {
  148.         xchar room;
  149.         xchar wall;
  150.         xchar door;
  151.     } corpos;
  152. }
  153.  
  154.  
  155. %token    <i> CHAR INTEGER BOOLEAN
  156. %token    <i> MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID
  157. %token    <i> OBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID
  158. %token    <i> MAZEWALK_ID WALLIFY_ID REGION_ID FILLING
  159. %token    <i> RANDOM_OBJECTS_ID RANDOM_MONSTERS_ID RANDOM_PLACES_ID
  160. %token    <i> ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID ROOM_ID
  161. %token    <i> PORTAL_ID TELEPRT_ID BRANCH_ID LEV CHANCE_ID
  162. %token    <i> CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE
  163. %token    <i> RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE
  164. %token    <i> DIRECTION RANDOM_TYPE O_REGISTER M_REGISTER P_REGISTER A_REGISTER
  165. %token    <i> ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN
  166. %token    <i> SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS
  167. %token    <i> MON_APPEARANCE
  168. %token    <i> ',' ':' '(' ')' '[' ']'
  169. %token    <map> STRING MAP_ID
  170. %type    <i> h_justif v_justif trap_name room_type door_state light_state
  171. %type    <i> alignment altar_type a_register roomfill filling door_pos
  172. %type    <i> door_wall walled secret curse_state enchantment amount
  173. %type    <i> engraving_type flags flag_list prefilled lev_region lev_init
  174. %type    <i> monster monster_c m_register object object_c o_register
  175. %type    <map> string maze_def level_def m_name o_name art_name
  176. %type    <corpos> corr_spec
  177. %start    file
  178.  
  179. %%
  180. file        : /* nothing */
  181.         | levels
  182.         ;
  183.  
  184. levels        : level
  185.         | level levels
  186.         ;
  187.  
  188. level        : maze_level
  189.         | room_level
  190.         ;
  191.  
  192. maze_level    : maze_def flags lev_init messages regions
  193.           {
  194.               int fout, i;
  195.  
  196.             if (fatal_error > 0) {
  197.                 fprintf(stderr,
  198.                   "%s : %d errors detected. No output created!\n",
  199.                     fname, fatal_error);
  200.             } else {
  201.                 char lbuf[20];
  202.                 Strcpy(lbuf, $1);
  203.                 Strcat(lbuf, LEV_EXT);
  204. #ifdef MAC_THINKC5
  205.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
  206. #else
  207.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
  208. #endif
  209.                 if (fout < 0) {
  210.                     yyerror("Can't open output file!!");
  211.                     exit(1);
  212.                 }
  213.                 maze.flags = $2;
  214.                 memcpy(&(maze.init_lev), &(init_lev),
  215.                        sizeof(lev_init));
  216.                 maze.numpart = npart;
  217.                 maze.parts = NewTab(mazepart, npart);
  218.                 for(i=0;i<npart;i++)
  219.                     maze.parts[i] = tmppart[i];
  220.                 write_maze(fout, &maze);
  221.                 (void) close(fout);
  222.                 npart = 0;
  223.             }
  224.           }
  225.         ;
  226.  
  227. room_level    : level_def flags lev_init messages rreg_init rooms corridors_def
  228.           {
  229.             int fout, i;
  230.  
  231.             if (fatal_error > 0) {
  232.                 fprintf(stderr,
  233.                   "%s : %d errors detected. No output created!\n",
  234.                     fname, fatal_error);
  235.             } else {
  236.                 char lbuf[20];
  237.                 Strcpy(lbuf, $1);
  238.                 Strcat(lbuf, LEV_EXT);
  239. #ifdef MAC_THINKC5
  240.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
  241. #else
  242.                 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
  243. #endif
  244.                 if (fout < 0) {
  245.                     yyerror("Can't open output file!!");
  246.                     exit(1);
  247.                 }
  248.                 special_lev.flags = $2;
  249.                 memcpy(&(special_lev.init_lev), &(init_lev),
  250.                        sizeof(lev_init));
  251.                 special_lev.nroom = nrooms;
  252.                 special_lev.rooms = NewTab(room, nrooms);
  253.                 for(i=0; i<nrooms; i++)
  254.                     special_lev.rooms[i] = tmproom[i];
  255.                 special_lev.ncorr = ncorridor;
  256.                 special_lev.corrs = NewTab(corridor, ncorridor);
  257.                 for(i=0; i<ncorridor; i++)
  258.                     special_lev.corrs[i] = tmpcor[i];
  259.                 if (check_subrooms())
  260.                     write_lev(fout, &special_lev);
  261.                 free_rooms(special_lev.rooms,special_lev.nroom);
  262.                 nrooms = 0;
  263.                 ncorridor = 0;
  264.                 (void) close(fout);
  265.             }
  266.           }
  267.         ;
  268.  
  269. level_def    : LEVEL_ID ':' string
  270.           {
  271.             if (index($3, '.'))
  272.                 yyerror("Invalid dot ('.') in level name.");
  273.             if (strlen($3) > 8)
  274.                 yyerror("Level names limited to 8 characters.");
  275.             $$ = $3;
  276.             special_lev.nrobjects = 0;
  277.             special_lev.nrmonst = 0;
  278.           }
  279.         ;
  280.  
  281. lev_init    : /* nothing */
  282.           {
  283.             init_lev.init_present = FALSE;
  284.             $$ = 0;
  285.           }
  286.         | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled
  287.           {
  288.             init_lev.init_present = TRUE;
  289.             if((init_lev.fg = what_map_char($3)) == INVALID_TYPE)
  290.                 yyerror("Invalid foreground type.");
  291.             if((init_lev.bg = what_map_char($5)) == INVALID_TYPE)
  292.                 yyerror("Invalid background type.");
  293.             init_lev.smoothed = $7;
  294.             init_lev.joined = $9;
  295.             init_lev.lit = $11;
  296.             init_lev.walled = $13;
  297.             $$ = 1;
  298.           }
  299.         ;
  300.  
  301. walled        : BOOLEAN
  302.         | RANDOM_TYPE
  303.         ;
  304.  
  305. flags        : /* nothing */
  306.           {
  307.             $$ = 0;
  308.           }
  309.         | FLAGS_ID ':' flag_list
  310.           {
  311.             $$ = lev_flags;
  312.           }
  313.         ;
  314.  
  315. flag_list    : FLAG_TYPE
  316.           {
  317.             lev_flags |= $1;
  318.           }
  319.         | FLAG_TYPE ',' flag_list
  320.           {
  321.             lev_flags |= $3;
  322.           }
  323.         ;
  324.  
  325. messages    : /* nothing */
  326.         | message messages
  327.         ;
  328.  
  329. message        : MESSAGE_ID ':' STRING
  330.           {
  331.             int i, j;
  332.  
  333.             i = strlen($3) + 1;
  334.             j = tmpmessage[0] ? strlen(tmpmessage) : 0;
  335.             if(i+j > 255) {
  336.                yyerror("Message string too long (>256 characters)");
  337.             } else {
  338.                 if(j) tmpmessage[j++] = '\n';
  339.                 strncpy(tmpmessage+j, $3, i-1);
  340.                 tmpmessage[j+i-1] = 0;
  341.             }
  342.           }
  343.         ;
  344.  
  345. rreg_init    : /* nothing */
  346.         | rreg_init init_rreg
  347.         ;
  348.  
  349. init_rreg    : RANDOM_OBJECTS_ID ':' object_list
  350.           {
  351.             if(special_lev.nrobjects) {
  352.                 yyerror("Object registers already initialized!");
  353.             } else {
  354.                 special_lev.nrobjects = n_olist;
  355.                 special_lev.robjects = (char *) alloc(n_olist);
  356.                 (void) memcpy((genericptr_t)special_lev.robjects,
  357.                       (genericptr_t)olist, n_olist);
  358.             }
  359.           }
  360.         | RANDOM_MONSTERS_ID ':' monster_list
  361.           {
  362.             if(special_lev.nrmonst) {
  363.                 yyerror("Monster registers already initialized!");
  364.             } else {
  365.                 special_lev.nrmonst = n_mlist;
  366.                 special_lev.rmonst = (char *) alloc(n_mlist);
  367.                 (void) memcpy((genericptr_t)special_lev.rmonst,
  368.                       (genericptr_t)mlist, n_mlist);
  369.               }
  370.           }
  371.         ;
  372.  
  373. rooms        : /* Nothing  -  dummy room for use with INIT_MAP */
  374.           {
  375.             tmproom[nrooms] = New(room);
  376.             (void) memset((genericptr_t) tmproom[nrooms], 0,
  377.                     sizeof *tmproom[nrooms]);
  378.             tmproom[nrooms]->name = (char *) 0;
  379.             tmproom[nrooms]->parent = (char *) 0;
  380.             tmproom[nrooms]->rtype = 0;
  381.             tmproom[nrooms]->rlit = 0;
  382.             tmproom[nrooms]->xalign = ERR;
  383.             tmproom[nrooms]->yalign = ERR;
  384.             tmproom[nrooms]->x = 0;
  385.             tmproom[nrooms]->y = 0;
  386.             tmproom[nrooms]->w = 2;
  387.             tmproom[nrooms]->h = 2;
  388.             in_room = 1;
  389.           }
  390.         | roomlist
  391.         ;
  392.  
  393. roomlist    : aroom
  394.         | aroom roomlist
  395.         ;
  396.  
  397. corridors_def    : random_corridors
  398.         | corridors
  399.         ;
  400.  
  401. random_corridors: RAND_CORRIDOR_ID
  402.           {
  403.             tmpcor[0] = New(corridor);
  404.             tmpcor[0]->src.room = -1;
  405.             ncorridor = 1;
  406.           }
  407.         ;
  408.  
  409. corridors    : /* nothing */
  410.         | corridors corridor
  411.         ;
  412.  
  413. corridor    : CORRIDOR_ID ':' corr_spec ',' corr_spec
  414.           {
  415.             tmpcor[ncorridor] = New(corridor);
  416.             tmpcor[ncorridor]->src.room = $3.room;
  417.             tmpcor[ncorridor]->src.wall = $3.wall;
  418.             tmpcor[ncorridor]->src.door = $3.door;
  419.             tmpcor[ncorridor]->dest.room = $5.room;
  420.             tmpcor[ncorridor]->dest.wall = $5.wall;
  421.             tmpcor[ncorridor]->dest.door = $5.door;
  422.             ncorridor++;
  423.           }
  424.         | CORRIDOR_ID ':' corr_spec ',' INTEGER
  425.           {
  426.             tmpcor[ncorridor]->src.room = $3.room;
  427.             tmpcor[ncorridor]->src.wall = $3.wall;
  428.             tmpcor[ncorridor]->src.door = $3.door;
  429.             tmpcor[ncorridor]->dest.room = -1;
  430.             tmpcor[ncorridor]->dest.wall = $5;
  431.             ncorridor++;
  432.           }
  433.         ;
  434.  
  435. corr_spec    : '(' INTEGER ',' DIRECTION ',' door_pos ')'
  436.           {
  437.             if ($2 >= nrooms)
  438.                 yyerror("Wrong room number!");
  439.             $$.room = $2;
  440.             $$.wall = $4;
  441.             $$.door = $6;
  442.           }
  443.         ;
  444.  
  445. aroom        : room_def room_details
  446.           {
  447.             store_room();
  448.           }
  449.         | subroom_def room_details
  450.           {
  451.             store_room();
  452.           }
  453.         ;
  454.  
  455. subroom_def    : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill
  456.           {
  457.             tmproom[nrooms] = New(room);
  458.             (void) memset((genericptr_t) tmproom[nrooms], 0,
  459.                     sizeof *tmproom[nrooms]);
  460.             tmproom[nrooms]->parent = dup_string($11);
  461.             tmproom[nrooms]->name = (char *) 0;
  462.             tmproom[nrooms]->rtype = $3;
  463.             tmproom[nrooms]->rlit = $5;
  464.             tmproom[nrooms]->filled = $12;
  465.             tmproom[nrooms]->xalign = ERR;
  466.             tmproom[nrooms]->yalign = ERR;
  467.             tmproom[nrooms]->x = current_coord.x;
  468.             tmproom[nrooms]->y = current_coord.y;
  469.             tmproom[nrooms]->w = current_size.width;
  470.             tmproom[nrooms]->h = current_size.height;
  471.             in_room = 1;
  472.           }
  473.         ;
  474.  
  475. room_def    : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill
  476.           {
  477.             tmproom[nrooms] = New(room);
  478.             (void) memset((genericptr_t) tmproom[nrooms], 0,
  479.                     sizeof *tmproom[nrooms]);
  480.             tmproom[nrooms]->name = (char *) 0;
  481.             tmproom[nrooms]->parent = (char *) 0;
  482.             tmproom[nrooms]->rtype = $3;
  483.             tmproom[nrooms]->rlit = $5;
  484.             tmproom[nrooms]->filled = $12;
  485.             tmproom[nrooms]->xalign = current_align.x;
  486.             tmproom[nrooms]->yalign = current_align.y;
  487.             tmproom[nrooms]->x = current_coord.x;
  488.             tmproom[nrooms]->y = current_coord.y;
  489.             tmproom[nrooms]->w = current_size.width;
  490.             tmproom[nrooms]->h = current_size.height;
  491.             in_room = 1;
  492.           }
  493.         ;
  494.  
  495. roomfill    : /* nothing */
  496.           {
  497.             $$ = 1;
  498.           }
  499.         | ',' BOOLEAN
  500.           {
  501.             $$ = $2;
  502.           }
  503.         ;
  504.  
  505. room_pos    : '(' INTEGER ',' INTEGER ')'
  506.           {
  507.             if ( $2 < 1 || $2 > 5 ||
  508.                 $4 < 1 || $4 > 5 ) {
  509.                 yyerror("Room position should be between 1 & 5!");
  510.             } else {
  511.                 current_coord.x = $2;
  512.                 current_coord.y = $4;
  513.             }
  514.           }
  515.         | RANDOM_TYPE
  516.           {
  517.             current_coord.x = current_coord.y = ERR;
  518.           }
  519.         ;
  520.  
  521. subroom_pos    : '(' INTEGER ',' INTEGER ')'
  522.           {
  523.             if ( $2 < 0 || $4 < 0) {
  524.                 yyerror("Invalid subroom position !");
  525.             } else {
  526.                 current_coord.x = $2;
  527.                 current_coord.y = $4;
  528.             }
  529.           }
  530.         | RANDOM_TYPE
  531.           {
  532.             current_coord.x = current_coord.y = ERR;
  533.           }
  534.         ;
  535.  
  536. room_align    : '(' h_justif ',' v_justif ')'
  537.           {
  538.             current_align.x = $2;
  539.             current_align.y = $4;
  540.           }
  541.         | RANDOM_TYPE
  542.           {
  543.             current_align.x = current_align.y = ERR;
  544.           }
  545.         ;
  546.  
  547. room_size    : '(' INTEGER ',' INTEGER ')'
  548.           {
  549.             current_size.width = $2;
  550.             current_size.height = $4;
  551.           }
  552.         | RANDOM_TYPE
  553.           {
  554.             current_size.height = current_size.width = ERR;
  555.           }
  556.         ;
  557.  
  558. room_details    : /* nothing */
  559.         | room_details room_detail
  560.         ;
  561.  
  562. room_detail    : room_name
  563.         | room_chance
  564.         | room_door
  565.         | monster_detail
  566.         | object_detail
  567.         | trap_detail
  568.         | altar_detail
  569.         | fountain_detail
  570.         | sink_detail
  571.         | pool_detail
  572.         | gold_detail
  573.         | engraving_detail
  574.         | stair_detail
  575.         ;
  576.  
  577. room_name    : NAME_ID ':' string
  578.           {
  579.             if (tmproom[nrooms]->name)
  580.                 yyerror("This room already has a name!");
  581.             else
  582.                 tmproom[nrooms]->name = dup_string($3);
  583.           }
  584.         ;
  585.  
  586. room_chance    : CHANCE_ID ':' INTEGER
  587.            {
  588.             if (tmproom[nrooms]->chance)
  589.                 yyerror("This room already assigned a chance!");
  590.             else if (tmproom[nrooms]->rtype == OROOM)
  591.                 yyerror("Only typed rooms can have a chance!");
  592.             else if ($3 < 1 || $3 > 99)
  593.                 yyerror("The chance is supposed to be precentile.");
  594.             else
  595.                 tmproom[nrooms]->chance = $3;
  596.            }
  597.         ;
  598.  
  599. room_door    : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
  600.           {
  601.             /* ERR means random here */
  602.             if ($7 == ERR && $9 != ERR) {
  603.              yyerror("If the door wall is random, so must be its pos!");
  604.             } else {
  605.                 tmprdoor[ndoor] = New(room_door);
  606.                 tmprdoor[ndoor]->secret = $3;
  607.                 tmprdoor[ndoor]->mask = $5;
  608.                 tmprdoor[ndoor]->wall = $7;
  609.                 tmprdoor[ndoor]->pos = $9;
  610.                 ndoor++;
  611.             }
  612.           }
  613.         ;
  614.  
  615. secret        : BOOLEAN
  616.         | RANDOM_TYPE
  617.         ;
  618.  
  619. door_wall    : DIRECTION
  620.         | RANDOM_TYPE
  621.         ;
  622.  
  623. door_pos    : INTEGER
  624.         | RANDOM_TYPE
  625.         ;
  626.  
  627. maze_def    : MAZE_ID ':' string ',' filling
  628.           {
  629.             maze.filling = $5;
  630.             if (index($3, '.'))
  631.                 yyerror("Invalid dot ('.') in level name.");
  632.             if (strlen($3) > 8)
  633.                 yyerror("Level names limited to 8 characters.");
  634.             $$ = $3;
  635.             in_room = 0;
  636.           }
  637.         ;
  638.  
  639. filling        : CHAR
  640.           {
  641.             $$ = get_floor_type((char)$1);
  642.           }
  643.         | RANDOM_TYPE
  644.           {
  645.             $$ = -1;
  646.           }
  647.         ;
  648.  
  649. regions        : aregion
  650.         | aregion regions
  651.         ;
  652.  
  653. aregion        : map_definition reg_init map_details
  654.           {
  655.             store_part();
  656.           }
  657.         ;
  658.  
  659. map_definition    : NOMAP_ID
  660.           {
  661.             tmppart[npart] = New(mazepart);
  662.             tmppart[npart]->halign = 1;
  663.             tmppart[npart]->valign = 1;
  664.             tmppart[npart]->nrobjects = 0;
  665.             tmppart[npart]->nloc = 0;
  666.             tmppart[npart]->nrmonst = 0;
  667.             tmppart[npart]->xsize = 1;
  668.             tmppart[npart]->ysize = 1;
  669.             tmppart[npart]->map = (char **) alloc(sizeof(char *));
  670.             tmppart[npart]->map[0] = (char *) alloc(1);
  671.             tmppart[npart]->map[0][0] = STONE;
  672.             max_x_map = COLNO-1;
  673.             max_y_map = ROWNO;
  674.           }
  675.         | map_geometry MAP_ID
  676.           {
  677.             tmppart[npart] = New(mazepart);
  678.             tmppart[npart]->halign = $<i>1 % 10;
  679.             tmppart[npart]->valign = $<i>1 / 10;
  680.             tmppart[npart]->nrobjects = 0;
  681.             tmppart[npart]->nloc = 0;
  682.             tmppart[npart]->nrmonst = 0;
  683.             scan_map($2);
  684.           }
  685.         ;
  686.  
  687. map_geometry    : GEOMETRY_ID ':' h_justif ',' v_justif
  688.           {
  689.             $<i>$ = $<i>3 + ($<i>5 * 10);
  690.           }
  691.         ;
  692.  
  693. h_justif    : LEFT_OR_RIGHT
  694.         | CENTER
  695.         ;
  696.  
  697. v_justif    : TOP_OR_BOT
  698.         | CENTER
  699.         ;
  700.  
  701. reg_init    : /* nothing */
  702.         | reg_init init_reg
  703.         ;
  704.  
  705. init_reg    : RANDOM_OBJECTS_ID ':' object_list
  706.           {
  707.             if (tmppart[npart]->nrobjects) {
  708.                 yyerror("Object registers already initialized!");
  709.             } else {
  710.                 tmppart[npart]->robjects = (char *)alloc(n_olist);
  711.                 (void) memcpy((genericptr_t)tmppart[npart]->robjects,
  712.                       (genericptr_t)olist, n_olist);
  713.                 tmppart[npart]->nrobjects = n_olist;
  714.             }
  715.           }
  716.         | RANDOM_PLACES_ID ':' place_list
  717.           {
  718.             if (tmppart[npart]->nloc) {
  719.                 yyerror("Location registers already initialized!");
  720.             } else {
  721.                 register int i;
  722.                 tmppart[npart]->rloc_x = (char *) alloc(n_plist);
  723.                 tmppart[npart]->rloc_y = (char *) alloc(n_plist);
  724.                 for(i=0;i<n_plist;i++) {
  725.                 tmppart[npart]->rloc_x[i] = plist[i].x;
  726.                 tmppart[npart]->rloc_y[i] = plist[i].y;
  727.                 }
  728.                 tmppart[npart]->nloc = n_plist;
  729.             }
  730.           }
  731.         | RANDOM_MONSTERS_ID ':' monster_list
  732.           {
  733.             if (tmppart[npart]->nrmonst) {
  734.                 yyerror("Monster registers already initialized!");
  735.             } else {
  736.                 tmppart[npart]->rmonst = (char *) alloc(n_mlist);
  737.                 (void) memcpy((genericptr_t)tmppart[npart]->rmonst,
  738.                       (genericptr_t)mlist, n_mlist);
  739.                 tmppart[npart]->nrmonst = n_mlist;
  740.             }
  741.           }
  742.         ;
  743.  
  744. object_list    : object
  745.           {
  746.             if (n_olist < MAX_REGISTERS)
  747.                 olist[n_olist++] = $<i>1;
  748.             else
  749.                 yyerror("Object list too long!");
  750.           }
  751.         | object ',' object_list
  752.           {
  753.             if (n_olist < MAX_REGISTERS)
  754.                 olist[n_olist++] = $<i>1;
  755.             else
  756.                 yyerror("Object list too long!");
  757.           }
  758.         ;
  759.  
  760. monster_list    : monster
  761.           {
  762.             if (n_mlist < MAX_REGISTERS)
  763.                 mlist[n_mlist++] = $<i>1;
  764.             else
  765.                 yyerror("Monster list too long!");
  766.           }
  767.         | monster ',' monster_list
  768.           {
  769.             if (n_mlist < MAX_REGISTERS)
  770.                 mlist[n_mlist++] = $<i>1;
  771.             else
  772.                 yyerror("Monster list too long!");
  773.           }
  774.         ;
  775.  
  776. place_list    : place
  777.           {
  778.             if (n_plist < MAX_REGISTERS)
  779.                 plist[n_plist++] = current_coord;
  780.             else
  781.                 yyerror("Location list too long!");
  782.           }
  783.         | place
  784.           {
  785.             if (n_plist < MAX_REGISTERS)
  786.                 plist[n_plist++] = current_coord;
  787.             else
  788.                 yyerror("Location list too long!");
  789.           }
  790.          ',' place_list
  791.         ;
  792.  
  793. map_details    : /* nothing */
  794.         | map_details map_detail
  795.         ;
  796.  
  797. map_detail    : monster_detail
  798.         | object_detail
  799.         | door_detail
  800.         | trap_detail
  801.         | drawbridge_detail
  802.         | region_detail
  803.         | stair_region
  804.         | portal_region
  805.         | teleprt_region
  806.         | branch_region
  807.         | altar_detail
  808.         | fountain_detail
  809.         | mazewalk_detail
  810.         | wallify_detail
  811.         | ladder_detail
  812.         | stair_detail
  813.         | gold_detail
  814.         | engraving_detail
  815.         | diggable_detail
  816.         ;
  817.  
  818. monster_detail    : MONSTER_ID ':' monster_c ',' m_name ',' coordinate
  819.           {
  820.             tmpmonst[nmons] = New(monster);
  821.             tmpmonst[nmons]->x = current_coord.x;
  822.             tmpmonst[nmons]->y = current_coord.y;
  823.             tmpmonst[nmons]->class = $<i>3;
  824.             tmpmonst[nmons]->peaceful = -1; /* no override */
  825.             tmpmonst[nmons]->asleep = -1;
  826.             tmpmonst[nmons]->align = - MAX_REGISTERS - 2;
  827.             tmpmonst[nmons]->name = (char *) 0;
  828.             tmpmonst[nmons]->appear = 0;
  829.             tmpmonst[nmons]->appear_as = (char *) 0;
  830.             if (!in_room)
  831.                 check_coord(current_coord.x, current_coord.y,
  832.                     "Monster");
  833.             if (!$5)
  834.                 tmpmonst[nmons]->id = -1;
  835.             else {
  836.                 int token = get_monster_id($5, (char) $<i>3);
  837.                 if (token == ERR) {
  838.                     yywarning("Illegal monster name!  Making random monster.");
  839.                     tmpmonst[nmons]->id = -1;
  840.                 } else
  841.                     tmpmonst[nmons]->id = token;
  842.             }
  843.           }
  844.          monster_infos
  845.           {
  846.             nmons++;
  847.           }
  848.         ;
  849.  
  850. monster_infos    : /* nothing */
  851.         | monster_infos monster_info
  852.         ;
  853.  
  854. monster_info    : ',' string
  855.           {
  856.             tmpmonst[nmons]->name = dup_string($2);
  857.           }
  858.         | ',' MON_ATTITUDE
  859.           {
  860.             tmpmonst[nmons]->peaceful = $<i>2;
  861.           }
  862.         | ',' MON_ALERTNESS
  863.           {
  864.             tmpmonst[nmons]->asleep = $<i>2;
  865.           }
  866.         | ',' alignment
  867.           {
  868.             tmpmonst[nmons]->align = $<i>2;
  869.           }
  870.         | ',' MON_APPEARANCE string
  871.           {
  872.             tmpmonst[nmons]->appear = $<i>2;
  873.             tmpmonst[nmons]->appear_as = dup_string($3);
  874.           }
  875.         ;
  876.  
  877. object_detail    : OBJECT_ID ':' object_c ',' o_name ',' coordinate
  878.           {
  879.             tmpobj[nobj] = New(object);
  880.             tmpobj[nobj]->x = current_coord.x;
  881.             tmpobj[nobj]->y = current_coord.y;
  882.             tmpobj[nobj]->class = $<i>3;
  883.             tmpobj[nobj]->corpsenm = -1;    /* init as none */
  884.             tmpobj[nobj]->curse_state = -1;
  885.             tmpobj[nobj]->name = (char *) 0;
  886.             if (!in_room)
  887.                 check_coord(current_coord.x, current_coord.y,
  888.                     "Object");
  889.             if (!$5)
  890.                 tmpobj[nobj]->id = -1;
  891.             else {
  892.                 int token = get_object_id($5);
  893.                 if (token == ERR) {
  894.                     yywarning("Illegal object name!  Making random object.");
  895.                     tmpobj[nobj]->id = -1;
  896.                 } else
  897.                     tmpobj[nobj]->id = token;
  898.             }
  899.           }
  900.          object_infos
  901.           {
  902.             nobj++;
  903.           }
  904.         ;
  905.  
  906. object_infos    : /* nothing */
  907.           {
  908.             tmpobj[nobj]->spe = -127;
  909.           }
  910.         | ',' STRING ',' enchantment
  911.           {
  912.             int token = get_monster_id($2, (char)0);
  913.             if (token == ERR)    /* "random" */
  914.                 tmpobj[nobj]->corpsenm = -2;
  915.             else
  916.                 tmpobj[nobj]->corpsenm = token;
  917.             tmpobj[nobj]->spe = $<i>4;
  918.           }
  919.         | ',' curse_state ',' enchantment ',' art_name
  920.           {
  921.             tmpobj[nobj]->curse_state = $<i>2;
  922.             tmpobj[nobj]->spe = $<i>4;
  923.             if ($6)
  924.                 tmpobj[nobj]->name = dup_string($6);
  925.             else
  926.                 tmpobj[nobj]->name = (char *) 0;
  927.           }
  928.         ;
  929.  
  930. curse_state    : RANDOM_TYPE
  931.         | CURSE_TYPE
  932.         ;
  933.  
  934. enchantment    : INTEGER
  935.         | RANDOM_TYPE
  936.           {
  937.             $<i>$ = -127;
  938.           }
  939.         ;
  940.  
  941. door_detail    : DOOR_ID ':' door_state ',' coordinate
  942.           {
  943.             tmpdoor[ndoor] = New(door);
  944.             tmpdoor[ndoor]->x = current_coord.x;
  945.             tmpdoor[ndoor]->y = current_coord.y;
  946.             tmpdoor[ndoor]->mask = $<i>3;
  947.             if(current_coord.x >= 0 && current_coord.y >= 0 &&
  948.                tmpmap[current_coord.y][current_coord.x] != DOOR &&
  949.                tmpmap[current_coord.y][current_coord.x] != SDOOR)
  950.                 yyerror("Door decl doesn't match the map");
  951.             ndoor++;
  952.           }
  953.         ;
  954.  
  955. trap_detail    : TRAP_ID ':' trap_name ',' coordinate
  956.           {
  957.             tmptrap[ntrap] = New(trap);
  958.             tmptrap[ntrap]->x = current_coord.x;
  959.             tmptrap[ntrap]->y = current_coord.y;
  960.             tmptrap[ntrap]->type = $<i>3;
  961.             if (!in_room)
  962.                 check_coord(current_coord.x, current_coord.y,
  963.                     "Trap");
  964.             ntrap++;
  965.           }
  966.         ;
  967.  
  968. drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state
  969.            {
  970.                 int x, y, dir;
  971.  
  972.             tmpdb[ndb] = New(drawbridge);
  973.             x = tmpdb[ndb]->x = current_coord.x;
  974.             y = tmpdb[ndb]->y = current_coord.y;
  975.             /* convert dir from a DIRECTION to a DB_DIR */
  976.             dir = $5;
  977.             switch(dir) {
  978.             case W_NORTH: dir = DB_NORTH; y--; break;
  979.             case W_SOUTH: dir = DB_SOUTH; y++; break;
  980.             case W_EAST:  dir = DB_EAST;  x++; break;
  981.             case W_WEST:  dir = DB_WEST;  x--; break;
  982.             default:
  983.                 yyerror("Invalid drawbridge direction");
  984.                 break;
  985.             }
  986.             tmpdb[ndb]->dir = dir;
  987.             if (current_coord.x >= 0 && current_coord.y >= 0 &&
  988.                 !IS_WALL(tmpmap[y][x])) {
  989.                 char ebuf[60];
  990.                 Sprintf(ebuf,
  991.                     "Wall needed for drawbridge (%02d, %02d)",
  992.                     current_coord.x, current_coord.y);
  993.                 yyerror(ebuf);
  994.             }
  995.  
  996.             if ( $<i>7 == D_ISOPEN )
  997.                 tmpdb[ndb]->db_open = 1;
  998.             else if ( $<i>7 == D_CLOSED )
  999.                 tmpdb[ndb]->db_open = 0;
  1000.             else
  1001.                 yyerror("A drawbridge can only be open or closed!");
  1002.             ndb++;
  1003.            }
  1004.         ;
  1005.  
  1006. mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION
  1007.           {
  1008.             tmpwalk[nwalk] = New(walk);
  1009.             tmpwalk[nwalk]->x = current_coord.x;
  1010.             tmpwalk[nwalk]->y = current_coord.y;
  1011.             tmpwalk[nwalk]->dir = $5;
  1012.             nwalk++;
  1013.           }
  1014.         ;
  1015.  
  1016. wallify_detail    : WALLIFY_ID
  1017.           {
  1018.             wallify_map();
  1019.           }
  1020.         ;
  1021.  
  1022. ladder_detail    : LADDER_ID ':' coordinate ',' UP_OR_DOWN
  1023.           {
  1024.             tmplad[nlad] = New(lad);
  1025.             tmplad[nlad]->x = current_coord.x;
  1026.             tmplad[nlad]->y = current_coord.y;
  1027.             tmplad[nlad]->up = $<i>5;
  1028.             if (!in_room)
  1029.                 check_coord(current_coord.x, current_coord.y,
  1030.                     "Ladder");
  1031.             nlad++;
  1032.           }
  1033.         ;
  1034.  
  1035. stair_detail    : STAIR_ID ':' coordinate ',' UP_OR_DOWN
  1036.           {
  1037.             tmpstair[nstair] = New(stair);
  1038.             tmpstair[nstair]->x = current_coord.x;
  1039.             tmpstair[nstair]->y = current_coord.y;
  1040.             tmpstair[nstair]->up = $<i>5;
  1041.             if (!in_room)
  1042.                 check_coord(current_coord.x, current_coord.y,
  1043.                     "Stairway");
  1044.             nstair++;
  1045.           }
  1046.         ;
  1047.  
  1048. stair_region    : STAIR_ID ':' lev_region
  1049.           {
  1050.             tmplreg[nlreg] = New(lev_region);
  1051.             tmplreg[nlreg]->in_islev = $3;
  1052.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1053.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1054.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1055.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1056.           }
  1057.          ',' lev_region ',' UP_OR_DOWN
  1058.           {
  1059.             tmplreg[nlreg]->del_islev = $6;
  1060.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1061.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1062.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1063.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1064.             if($8)
  1065.                 tmplreg[nlreg]->rtype = LR_UPSTAIR;
  1066.             else
  1067.                 tmplreg[nlreg]->rtype = LR_DOWNSTAIR;
  1068.             tmplreg[nlreg]->rname = 0;
  1069.             nlreg++;
  1070.           }
  1071.         ;
  1072.  
  1073. portal_region    : PORTAL_ID ':' lev_region
  1074.           {
  1075.             tmplreg[nlreg] = New(lev_region);
  1076.             tmplreg[nlreg]->in_islev = $3;
  1077.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1078.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1079.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1080.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1081.           }
  1082.          ',' lev_region ',' string
  1083.           {
  1084.             tmplreg[nlreg]->del_islev = $6;
  1085.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1086.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1087.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1088.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1089.             tmplreg[nlreg]->rtype = LR_PORTAL;
  1090.             tmplreg[nlreg]->rname = $8;
  1091.             nlreg++;
  1092.           }
  1093.         ;
  1094.  
  1095. teleprt_region    : TELEPRT_ID ':' lev_region
  1096.           {
  1097.             tmplreg[nlreg] = New(lev_region);
  1098.             tmplreg[nlreg]->in_islev = $3;
  1099.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1100.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1101.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1102.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1103.           }
  1104.          ',' lev_region
  1105.           {
  1106.             tmplreg[nlreg]->del_islev = $6;
  1107.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1108.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1109.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1110.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1111.           }
  1112.         teleprt_detail
  1113.           {
  1114.             switch($<i>8) {
  1115.             case -1: tmplreg[nlreg]->rtype = LR_TELE; break;
  1116.             case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break;
  1117.             case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break;
  1118.             }
  1119.             tmplreg[nlreg]->rname = 0;
  1120.             nlreg++;
  1121.           }
  1122.         ;
  1123.  
  1124. branch_region    : BRANCH_ID ':' lev_region
  1125.           {
  1126.             tmplreg[nlreg] = New(lev_region);
  1127.             tmplreg[nlreg]->in_islev = $3;
  1128.             tmplreg[nlreg]->inarea.x1 = current_region.x1;
  1129.             tmplreg[nlreg]->inarea.y1 = current_region.y1;
  1130.             tmplreg[nlreg]->inarea.x2 = current_region.x2;
  1131.             tmplreg[nlreg]->inarea.y2 = current_region.y2;
  1132.           }
  1133.          ',' lev_region
  1134.           {
  1135.             tmplreg[nlreg]->del_islev = $6;
  1136.             tmplreg[nlreg]->delarea.x1 = current_region.x1;
  1137.             tmplreg[nlreg]->delarea.y1 = current_region.y1;
  1138.             tmplreg[nlreg]->delarea.x2 = current_region.x2;
  1139.             tmplreg[nlreg]->delarea.y2 = current_region.y2;
  1140.             tmplreg[nlreg]->rtype = LR_BRANCH;
  1141.             tmplreg[nlreg]->rname = 0;
  1142.             nlreg++;
  1143.           }
  1144.         ;
  1145.  
  1146. teleprt_detail    : /* empty */
  1147.           {
  1148.             $<i>$ = -1;
  1149.           }
  1150.         | ',' UP_OR_DOWN
  1151.           {
  1152.             $<i>$ = $2;
  1153.           }
  1154.         ;
  1155.  
  1156. lev_region    : region
  1157.           {
  1158.             $$ = 0;
  1159.           }
  1160.         | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
  1161.           {
  1162. /* This series of if statements is a hack for MSC 5.1.  It seems that its
  1163.    tiny little brain cannot compile if these are all one big if statement. */
  1164.             if ($3 <= 0 || $3 >= COLNO)
  1165.                 yyerror("Region out of level range!");
  1166.             else if ($5 < 0 || $5 >= ROWNO)
  1167.                 yyerror("Region out of level range!");
  1168.             else if ($7 <= 0 || $7 >= COLNO)
  1169.                 yyerror("Region out of level range!");
  1170.             else if ($9 < 0 || $9 >= ROWNO)
  1171.                 yyerror("Region out of level range!");
  1172.             current_region.x1 = $3;
  1173.             current_region.y1 = $5;
  1174.             current_region.x2 = $7;
  1175.             current_region.y2 = $9;
  1176.             $$ = 1;
  1177.           }
  1178.         ;
  1179.  
  1180. fountain_detail : FOUNTAIN_ID ':' coordinate
  1181.           {
  1182.             tmpfountain[nfountain] = New(fountain);
  1183.             tmpfountain[nfountain]->x = current_coord.x;
  1184.             tmpfountain[nfountain]->y = current_coord.y;
  1185.             if (!in_room)
  1186.                 check_coord(current_coord.x, current_coord.y,
  1187.                     "Fountain");
  1188.             nfountain++;
  1189.           }
  1190.         ;
  1191.  
  1192. sink_detail : SINK_ID ':' coordinate
  1193.           {
  1194.             tmpsink[nsink] = New(sink);
  1195.             tmpsink[nsink]->x = current_coord.x;
  1196.             tmpsink[nsink]->y = current_coord.y;
  1197.             nsink++;
  1198.           }
  1199.         ;
  1200.  
  1201. pool_detail : POOL_ID ':' coordinate
  1202.           {
  1203.             tmppool[npool] = New(pool);
  1204.             tmppool[npool]->x = current_coord.x;
  1205.             tmppool[npool]->y = current_coord.y;
  1206.             npool++;
  1207.           }
  1208.         ;
  1209.  
  1210. diggable_detail : NON_DIGGABLE_ID ':' region
  1211.           {
  1212.             tmpdig[ndig] = New(digpos);
  1213.             tmpdig[ndig]->x1 = current_region.x1;
  1214.             tmpdig[ndig]->y1 = current_region.y1;
  1215.             tmpdig[ndig]->x2 = current_region.x2;
  1216.             tmpdig[ndig]->y2 = current_region.y2;
  1217.             ndig++;
  1218.           }
  1219.         ;
  1220.  
  1221. region_detail    : REGION_ID ':' region ',' light_state ',' room_type prefilled
  1222.           {
  1223.             tmpreg[nreg] = New(region);
  1224.             tmpreg[nreg]->x1 = current_region.x1;
  1225.             tmpreg[nreg]->y1 = current_region.y1;
  1226.             tmpreg[nreg]->x2 = current_region.x2;
  1227.             tmpreg[nreg]->y2 = current_region.y2;
  1228.             tmpreg[nreg]->rlit = $<i>5;
  1229.             tmpreg[nreg]->rtype = $<i>7;
  1230.             if($<i>8 & 1) tmpreg[nreg]->rtype += MAXRTYPE+1;
  1231.             tmpreg[nreg]->rirreg = (($<i>8 & 2) != 0);
  1232.             if(current_region.x1 > current_region.x2 ||
  1233.                current_region.y1 > current_region.y2)
  1234.                yyerror("Region start > end!");
  1235.             if(tmpreg[nreg]->rtype == VAULT &&
  1236.                (tmpreg[nreg]->rirreg ||
  1237.                 (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) ||
  1238.                 (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1)))
  1239.                 yyerror("Vaults must be exactly 2x2!");
  1240.             if(want_warnings && !tmpreg[nreg]->rirreg &&
  1241.                current_region.x1 > 0 && current_region.y1 > 0 &&
  1242.                current_region.x2 < max_x_map &&
  1243.                current_region.y2 < max_y_map) {
  1244.                 /* check for walls in the room */
  1245.                 char ebuf[60];
  1246.                 register int x, y, nrock = 0;
  1247.  
  1248.                 for(y=current_region.y1; y<=current_region.y2; y++)
  1249.                 for(x=current_region.x1;
  1250.                     x<=current_region.x2; x++)
  1251.                     if(IS_ROCK(tmpmap[y][x]) ||
  1252.                        IS_DOOR(tmpmap[y][x])) nrock++;
  1253.                 if(nrock) {
  1254.                 Sprintf(ebuf,
  1255.                     "Rock in room (%02d,%02d,%02d,%02d)?!",
  1256.                     current_region.x1, current_region.y1,
  1257.                     current_region.x2, current_region.y2);
  1258.                 yywarning(ebuf);
  1259.                 }
  1260.                 if (
  1261.         !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) ||
  1262.         !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) ||
  1263.         !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) ||
  1264.         !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) {
  1265.                 Sprintf(ebuf,
  1266.                 "NonRock edge in room (%02d,%02d,%02d,%02d)?!",
  1267.                     current_region.x1, current_region.y1,
  1268.                     current_region.x2, current_region.y2);
  1269.                 yywarning(ebuf);
  1270.                 }
  1271.             } else if(tmpreg[nreg]->rirreg &&
  1272.         !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) {
  1273.                 char ebuf[60];
  1274.                 Sprintf(ebuf,
  1275.                     "Rock in irregular room (%02d,%02d)?!",
  1276.                     current_region.x1, current_region.y1);
  1277.                 yyerror(ebuf);
  1278.             }
  1279.             nreg++;
  1280.           }
  1281.         ;
  1282.  
  1283. altar_detail    : ALTAR_ID ':' coordinate ',' alignment ',' altar_type
  1284.           {
  1285.             tmpaltar[naltar] = New(altar);
  1286.             tmpaltar[naltar]->x = current_coord.x;
  1287.             tmpaltar[naltar]->y = current_coord.y;
  1288.             tmpaltar[naltar]->align = $<i>5;
  1289.             tmpaltar[naltar]->shrine = $<i>7;
  1290.             if (!in_room)
  1291.                 check_coord(current_coord.x, current_coord.y,
  1292.                     "Altar");
  1293.             naltar++;
  1294.           }
  1295.         ;
  1296.  
  1297. gold_detail    : GOLD_ID ':' amount ',' coordinate
  1298.           {
  1299.             tmpgold[ngold] = New(gold);
  1300.             tmpgold[ngold]->x = current_coord.x;
  1301.             tmpgold[ngold]->y = current_coord.y;
  1302.             tmpgold[ngold]->amount = $<i>3;
  1303.             if (!in_room)
  1304.                 check_coord(current_coord.x, current_coord.y,
  1305.                     "Gold");
  1306.             ngold++;
  1307.           }
  1308.         ;
  1309.  
  1310. engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string
  1311.           {
  1312.             tmpengraving[nengraving] = New(engraving);
  1313.             tmpengraving[nengraving]->x = current_coord.x;
  1314.             tmpengraving[nengraving]->y = current_coord.y;
  1315.             tmpengraving[nengraving]->e.text = $7;
  1316.             tmpengraving[nengraving]->etype = $<i>5;
  1317.             if (!in_room)
  1318.                 check_coord(current_coord.x, current_coord.y,
  1319.                     "Engraving");
  1320.             nengraving++;
  1321.           }
  1322.         ;
  1323.  
  1324. monster_c    : monster
  1325.         | RANDOM_TYPE
  1326.           {
  1327.             $<i>$ = - MAX_REGISTERS - 1;
  1328.           }
  1329.         | m_register
  1330.         ;
  1331.  
  1332. object_c    : object
  1333.         | RANDOM_TYPE
  1334.           {
  1335.             $<i>$ = - MAX_REGISTERS - 1;
  1336.           }
  1337.         | o_register
  1338.         ;
  1339.  
  1340. m_name        : string
  1341.         | RANDOM_TYPE
  1342.           {
  1343.             $$ = (char *) 0;
  1344.           }
  1345.         ;
  1346.  
  1347. o_name        : string
  1348.         | RANDOM_TYPE
  1349.           {
  1350.             $$ = (char *) 0;
  1351.           }
  1352.         ;
  1353.  
  1354. trap_name    : string
  1355.           {
  1356.             int token = get_trap_type($1);
  1357.             if (token == ERR)
  1358.                 yyerror("Unknown trap type!");
  1359.             $<i>$ = token;
  1360.           }
  1361.         | RANDOM_TYPE
  1362.         ;
  1363.  
  1364. room_type    : string
  1365.           {
  1366.             int token = get_room_type($1);
  1367.             if (token == ERR) {
  1368.                 yywarning("Unknown room type!  Making ordinary room...");
  1369.                 $<i>$ = OROOM;
  1370.             } else
  1371.                 $<i>$ = token;
  1372.           }
  1373.         | RANDOM_TYPE
  1374.         ;
  1375.  
  1376. prefilled    : /* empty */
  1377.           {
  1378.             $<i>$ = 0;
  1379.           }
  1380.         | ',' FILLING
  1381.           {
  1382.             $<i>$ = $2;
  1383.           }
  1384.         | ',' FILLING ',' BOOLEAN
  1385.           {
  1386.             $<i>$ = $2 + ($4 << 1);
  1387.           }
  1388.         ;
  1389.  
  1390. coordinate    : coord
  1391.         | p_register
  1392.         | RANDOM_TYPE
  1393.           {
  1394.             current_coord.x = current_coord.y = -MAX_REGISTERS-1;
  1395.           }
  1396.         ;
  1397.  
  1398. door_state    : DOOR_STATE
  1399.         | RANDOM_TYPE
  1400.         ;
  1401.  
  1402. light_state    : LIGHT_STATE
  1403.         | RANDOM_TYPE
  1404.         ;
  1405.  
  1406. alignment    : ALIGNMENT
  1407.         | a_register
  1408.         | RANDOM_TYPE
  1409.           {
  1410.             $<i>$ = - MAX_REGISTERS - 1;
  1411.           }
  1412.         ;
  1413.  
  1414. altar_type    : ALTAR_TYPE
  1415.         | RANDOM_TYPE
  1416.         ;
  1417.  
  1418. p_register    : P_REGISTER '[' INTEGER ']'
  1419.           {
  1420.             if ( $3 >= MAX_REGISTERS )
  1421.                 yyerror("Register Index overflow!");
  1422.             else
  1423.                 current_coord.x = current_coord.y = - $3 - 1;
  1424.           }
  1425.         ;
  1426.  
  1427. o_register    : O_REGISTER '[' INTEGER ']'
  1428.           {
  1429.             if ( $3 >= MAX_REGISTERS )
  1430.                 yyerror("Register Index overflow!");
  1431.             else
  1432.                 $<i>$ = - $3 - 1;
  1433.           }
  1434.         ;
  1435.  
  1436. m_register    : M_REGISTER '[' INTEGER ']'
  1437.           {
  1438.             if ( $3 >= MAX_REGISTERS )
  1439.                 yyerror("Register Index overflow!");
  1440.             else
  1441.                 $<i>$ = - $3 - 1;
  1442.           }
  1443.         ;
  1444.  
  1445. a_register    : A_REGISTER '[' INTEGER ']'
  1446.           {
  1447.             if ( $3 >= 3 )
  1448.                 yyerror("Register Index overflow!");
  1449.             else
  1450.                 $<i>$ = - $3 - 1;
  1451.           }
  1452.         ;
  1453.  
  1454. place        : coord
  1455.         ;
  1456.  
  1457. monster        : CHAR
  1458.           {
  1459.             if (check_monster_char((char) $1))
  1460.                 $<i>$ = $1 ;
  1461.             else {
  1462.                 yyerror("Unknown monster class!");
  1463.                 $<i>$ = ERR;
  1464.             }
  1465.           }
  1466.         ;
  1467.  
  1468. object        : CHAR
  1469.           {
  1470.             char c = $1;
  1471.             if (check_object_char(c))
  1472.                 $<i>$ = c;
  1473.             else {
  1474.                 yyerror("Unknown char class!");
  1475.                 $<i>$ = ERR;
  1476.             }
  1477.           }
  1478.         ;
  1479.  
  1480. string        : STRING
  1481.         ;
  1482.  
  1483. art_name    : STRING
  1484.         | NONE
  1485.           {
  1486.             $$ = (char *) 0;
  1487.           }
  1488.         ;
  1489.  
  1490. amount        : INTEGER
  1491.         | RANDOM_TYPE
  1492.         ;
  1493.  
  1494. engraving_type    : ENGRAVING_TYPE
  1495.         | RANDOM_TYPE
  1496.         ;
  1497.  
  1498. coord        : '(' INTEGER ',' INTEGER ')'
  1499.           {
  1500.             if (!in_room && !init_lev.init_present &&
  1501.                 ($2 < 0 || $2 > max_x_map ||
  1502.                  $4 < 0 || $4 > max_y_map))
  1503.                 yyerror("Coordinates out of map range!");
  1504.             current_coord.x = $2;
  1505.             current_coord.y = $4;
  1506.           }
  1507.         ;
  1508.  
  1509. region        : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
  1510.           {
  1511. /* This series of if statements is a hack for MSC 5.1.  It seems that its
  1512.    tiny little brain cannot compile if these are all one big if statement. */
  1513.             if ($2 < 0 || $2 > max_x_map)
  1514.                 yyerror("Region out of map range!");
  1515.             else if ($4 < 0 || $4 > max_y_map)
  1516.                 yyerror("Region out of map range!");
  1517.             else if ($6 < 0 || $6 > max_x_map)
  1518.                 yyerror("Region out of map range!");
  1519.             else if ($8 < 0 || $8 > max_y_map)
  1520.                 yyerror("Region out of map range!");
  1521.             current_region.x1 = $2;
  1522.             current_region.y1 = $4;
  1523.             current_region.x2 = $6;
  1524.             current_region.y2 = $8;
  1525.           }
  1526.         ;
  1527.  
  1528. %%
  1529.